Informe Hito III

  • Curso: CC5206-1 Introducción a la Minería de Datos
  • Profesores: Bárbara Poblete - Felipe Bravo
  • Auxiliares: Hernán Sarmiento - Juglar Díaz - Mauricio Quezada
  • Integrantes: Carlos Barría - Joaquín Jil - Timothé Degiorgis

Introducción

No es novedad que las redes sociales desde la primera década de este siglo han cobrado gran importancia en la vidas de las personas, interactuando con ellas de forma cotidiana. Por lo tanto, los análisis y la utilidad que se pueden sacar a ellas pueden llegar a ser de enorme importancia para empresas, instituciones públicas, partidos políticos, etc.

En el presente trabajo se aborda una problemática latente de varios países en el mundo, como lo son los ataques terroristas. Específicamente se busca, utilizando datos generados a través de Twitter, hacer un estudio de cuatro grandes atentados que afectaron a Inglaterra durante el año 2017; específicamente se estudiarán los atentados de Finsbury Park (19 de junio), London Bridge (3 de junio), Manchester Arena (22 de mayo) y Westminster (22 de mayo), los cuales a priori están relacionados a ataques islamófobos o yihadistas. Estos atentados se inscriben en una serie de ataques en Europa que empezó en 2015, impulsado por el Estado Islámico.

En este proyecto, en particular, se busca:

  1. Utilizar la aplicación de herramientas de minería de datos para poder obtener modelos que permitan predecir ciertos comportamientos como lo son si un usuario publica un "tweet" sobre un atentado terrorista o no.
  2. Evaluar las variaciones de los estados de ánimo antes y posterior a un atentado terrorista.

Los modelos y los resultados son expuesto a continuación en este trabajo.

Objetivos

  1. Determinar si existe una variación significativa en los sentimientos de los tweets antes y después de un atentado terrorista.
  2. Crear un clasificador que permita determinar si efectivamente un tweet hace referencia a un evento terrorista o no.

Data

Caracterización

La base de datos a trabajar para este hito fueron los ataque terroristas ,en Inglaterra ocurridos durante el 2017, estos corresponden al registro de mas de 60000 tweets por cada ataque registrados bajo la búsqueda de 4 keywords relacionadas al ataque, por ejemplo para el caso de finsbury se tiene "terrorist", "attack", "finsbury", "london". Dicho esto los atributos utilizados para caracterizar los tweets son los siguientes:

  1. class: variable dummy que indica si un tweet hace referencia a un atentado terrorista (1) o no (0)
  2. creation_date: fecha de emisión del tweet en formato "YYYY-MM-DD hr:min:sec"
  3. download_date : análogo a fecha de creación pero en relación a la descarga del tweet, este atributo es importante ya que un tweet puede cambiar en función del tiempo, específicamente el número de respuestas y retweets depende de cuando descargue el tweet.
  4. id_tweet: identificador único para cada tweet.
  5. Id_user: identificador único para cada user.
  6. text_tweet: texto del tweet.
  7. rt_count: número de retweets.
  8. src_text : origen del tweet, desde qué dispositivo se envió smartphone, web, etc.
  9. followers_count: cantidad de “followers” por usuario.

Es necesario recalcar el hecho de que el atributo class fue creado de manera manual por los integrantes del grupo, pero para esta iteracion del proyecto solo se consideraron 100 tweets por hora lo cual es equivalente a 2400 tweets por cada atentado.

Preprocesamiento

Antes de proceder con el analisis y clasificación fue necesario limpiar nuestro dataset lo cual consistió en dos principales etapas.

  1. Eliminar tweets repetidos. Esto se debe a que dentro del dataset muchos tweets fueron descargados más de una vez. Para solucionar esto fue necesario eliminar todos los tweets repetido conservando solo el tweet con la última fecha de descarga.
  2. Crear archivos que contengan bloques de tweets durante un intervalo de tiempo de 1 hora. Para uno de los análisis que se realizaron durante este hito fue necesario generar archivos con los tweets emitidos durante cierto intervalo de tiempo, en este caso durante intervalos de una hora, para esto se agruparon los tweets usando el atributo "creation_date" y luego se guardaron en archivos de texto plano con nombre n.txt con n de 0 a 23.

Análisis de sentimientos

En esta parte del trabajo, se muestra el código utilizado para poder levantar información sobre la evolución de los sentimientos en los tweets publicados durente un horizonte temporal anterior y posterior al atentado terrorista ocurrido en Finsbury Park el año 2017. Como se mencionó anteriormente, se trabaja solo con esta base de datos debido a que se requiere hacer una clasificación manual de los datos y, a modo de ejemplificar el uso de las diversas herramientas aprendidas, basta para este hito la utilización de la base de datos de un solo atentado terrorista.

In [1]:
# unzip if necesary
# !unzip data.zip
In [2]:
#Test lbsa lib
# https://github.com/AntoinePassemiers/Lexicon-Based-Sentiment-Analysis

#Importar librerías

import numpy as np
import pandas as pd
import lbsa
import matplotlib.pyplot as plt
import seaborn as sn

import codecs
import string

import time

from calendar import timegm
#from google.colab import files
from scipy.stats import t

%matplotlib inline

A continuación se muestro un ejemplo de la utilización de la libreria lbsa (lexicon based sentiment analysis), en conjunto con lexicons de NRC, con la finalidad de econtrar un vector de caracteristicas compuesto por :

['anger' , 'anticipation', 'disgust', 'fear', 'joy', 'sadness', 'surprise' 'trust', 'positive', 'negative' ]

In [4]:
sa_lexicon = lbsa.get_lexicon('sa', language='english', source='nrc')
op_lexicon = lbsa.get_lexicon('opinion', language='english', source='nrc')


tweet = """
The Budget Agreement today is so important for our great Military.
It ends the dangerous sequester and gives Secretary Mattis what he needs to keep America Great.
Republicans and Democrats must support our troops and support this Bill!
 """

extractor = lbsa.FeatureExtractor(sa_lexicon, op_lexicon)
extractor.process(tweet)
Out[4]:
array([0., 0., 0., 2., 0., 0., 0., 3., 2., 1.])

Con lo anterior sumado a nuestro dataset con los tweets, se utilizó un pequeño script que genera 24 archivos de texto que contienen los tweets en un intervalo de 1 hora, luego se aplicó el análisis de sentimiento presentado anteriormente sobre estos bloques de tweets con la finalidad de estudiar el comportamiento durantes las 12 horas previas y las 12 horas posteriores al atentado.

Cabe destacar que para poder evaluar si las diferencias son significativas para el caso de los sentimientos de "miedo" e "ira", se realizó un test de diferencias de medias. La distribución del estimador para este caso fue una t de Student debido a que el tamaño de la muestra es menor a 30 (24) para haber escogido una normal.

A continuación son mostrados los gráficos juntos a los p-valores para los sentimientos en cuestión. Cabe destacar que el p-valor corresponde que la hipótesis nula (en este caso, que el promedio de los sentimientos son iguales antes y después del atentado) sea cierta y, en este caso, toleraremos un error del 5% o 0,05.

In [5]:
def dependent_ttest(data1, data2, alpha):
	# calculate means
	mean1, mean2 = np.mean(data1), np.mean(data2)
	# number of paired samples
	n = len(data1)
	# sum squared difference between observations
	d1 = sum([(data1[i]-data2[i])**2 for i in range(n)])
	# sum difference between observations
	d2 = sum([data1[i]-data2[i] for i in range(n)])
	# standard deviation of the difference between means
	sd = np.sqrt((d1 - (d2**2 / n)) / (n - 1))
	# standard error of the difference between the means
	sed = sd / np.sqrt(n)
	# calculate the t statistic
	t_stat = (mean1 - mean2) / sed
	# degrees of freedom
	df = n - 1
	# calculate the critical value
	cv = t.ppf(1.0 - alpha, df)
	# calculate the p-value
	p = (1.0 - t.cdf(abs(t_stat), df)) * 2.0
	# return everything
	return p

Esta función sirve para graficar temporalmente la evolución de los grados de las emociones de los tweets, además se le aplica el test de hipótesis anteriomente nombrado.

In [6]:
def get_sentiment(src_data, place):

  lexicon = lbsa.get_lexicon('sa', language='english')
  op_lexicon = lbsa.get_lexicon('opinion', language='english', source='nrc')
  tag_names = lexicon.get_tag_names()

  dict_feat = {'anger':[], 'anticipation':[], 'disgust':[], 'fear':[], 'joy':[], 'sadness':[], 'surprise':[], 'trust':[]}

  len_text_array = []
  for i in range(24):
      try:
          f = open(src_data + str(i) +".txt", 'r',encoding='utf-8') 
          text = f.read()
          text = text.encode("ascii", errors="ignore").decode()

          # El largo de los textos va a servir para normalizar
          len_text = len(text.split())
          len_text_array.append(len_text)

          extractor = lbsa.FeatureExtractor(lexicon, op_lexicon)

          tmp_feat = (lexicon.process(text))
          for feature_name in tag_names: 
              dict_feat[feature_name].append(tmp_feat[feature_name])
      except:
          break


  #print(dict_feat)
  x_label = np.subtract(range(24), 12)
  for feature_name in tag_names: 
      feature = (dict_feat[feature_name])
      #print(feature)
      plt.plot(x_label, feature, label=feature_name)

  plt.title(place)
  plt.legend()
  plt.xlabel("Hora relativa")
  plt.ylabel("Presencia sentimiento")
  plt.show()
  feature = (np.divide(dict_feat['fear'],len_text_array))
  p1 = feature[range(0,12)]
  p2 = feature[range(12,24)]
  print('Miedo: p-valor:', dependent_ttest(p1,p2,0.05))
  
  feature = (np.divide(dict_feat['anger'],len_text_array))
  p1 = feature[range(0,12)]
  p2 = feature[range(12,24)]
  print('Rabia: p-valor:', dependent_ttest(p1,p2,0.05))
  
In [7]:
fins_path = "data/fins/"
get_sentiment(fins_path, "finsbury")

fins_path = "data/man/"
get_sentiment(fins_path, "manchester")

fins_path = "data/london/"
get_sentiment(fins_path, "london")

fins_path = "data/west/"
get_sentiment(fins_path, "westminster")
Miedo: p-valor: 0.006416669201438685
Rabia: p-valor: 7.045517573511795e-05
Miedo: p-valor: 0.007583100135056586
Rabia: p-valor: 0.09898956270913017
Miedo: p-valor: 0.00023263407727691643
Rabia: p-valor: 0.32175906309237723
Miedo: p-valor: 5.355793402839204e-05
Rabia: p-valor: 0.00100739822834095

Esta vez los dataset contienen solo 100 tweets por hora para cada atentado, por lo cual no es necesario normalizar.

Se desprende del análisis de sentimientos lo siguiente:

  1. Los sentimientos de miedo y enojo son los principales para todos los intervalos de tiempo, ya sean normalizados o no los gráficos.
  2. Respecto al gráfico no normalizado, se puede observar que los primeros intervalos de tiempo posterior al atentado tengan un "peak", lo cual resulta razonable debido a que es un hecho noticioso que se encuentra recién ocurriendo y concita la atención pública. Pero en el gráfico se puede desprender también que existe uno posterior a las 8 horas y este se puede explicar debido a que el atentado de Finsbury ocurrió a las 12:15 a.m (hora local), por lo tanto, a las 08:15 a.m. las reacciones del atentado ocurren en un periodo donde la gente comienza su jornada laboral, lo cual explica el alto nivel de actividad.
  3. Para la emoción de miedo, todas las diferencias son significativas al 95%. En cambio, en el caso de la ira hubo dos casos donde no se cumple las diferencias, las cuales son Londres y Manchester; estas diferencias se pueden deber a los eventos anteriores que ensucian la data como por ejemplo: el concierto de Ariana Grande y el atentado de Manchester.

Métodos de clasificación

Conclusión respecto a las modelos de clasificación

En el hito anterior se utilizaron cuatro modelos de clasificación, los cuales son: redes neuronales, support vector machine, árboles de decisión y naive bayes. Los cuales fueron ejecutadas y evaluados a través de métricas como el accuracy, precision y recall. De ellos se obtuvieron las siguiente conclusiones:

De los resultados de las métricas, se puede mencionar que:

  1. Los modelos con mejor accuracy fueron el de redes neuronales y el support vector machine con un valor aproximado de 0.82.
  2. Los modelos con mejor precision fueron nuevamente la red neuronal y la SVM con 0.75 para la clase 1.
  3. Los modelos con mejor recall fueron SVM y el de redes neuronales con 0.85
  4. Árboles de desición y naive Bayes entregaron resultados bastante mediocres en comparación con los 2 métodos mencionados anteriormente.

Considerando esto los experimentos realizados para este último hito solo consideraron los modelos que entregaron mejores resultados, redes neuronales y SVN.

A continuación se presentan los resultdos que se obtuvieron al utilizar dichos clasificadores sobre el nuevo dataset híbrido que incluye los cuatro atentados.

In [9]:
filecp = codecs.open("data/merge.tsv", encoding = 'utf8')
data = pd.read_csv(filecp, sep="\t", encoding="utf-8", )
data.reset_index(drop=True)

# Creamos un arreglo vacío en el que se agregaran los vectores con los atributos
# usados durante el entrenamiento para cada fila
data_array = []

# Obtenemos la cantidad de filas
rows = data["class"].count()
print("Total filas: ", rows)

src_text_dict = {
                "Twitter for iPhone":0,
                "Twitter Web Client":1,
                "Twitter for Android":2
                }

sa_lexicon = lbsa.get_lexicon('sa', language='english', source='nrc')
op_lexicon = lbsa.get_lexicon('opinion', language='english', source='nrc')

# Guardamos un txt con todos los tweets,a brimos el archivo en modo "append"

# Limpiamos el txt
open("text_tweets.txt", 'w').close()
f = open("text_tweets.txt", "a")

for i in range(rows):
    rt_count = data.loc[i,"rt_count"] if data.loc[i,"rt_count"] else 0
    followers_count = data.loc[i,"followers_count"] if data.loc[i,"followers_count"] else 0
    #epoch_time = timegm(time.strptime(data.loc[i,"creation_date"], "%Y-%m-%d %H:%M:%S")) if data.loc[i,"creation_date"] else 0
    tmp_row = [rt_count, followers_count]
    
    src = data.loc[i,"src_text"]
    txt_src = src_text_dict[src] if src in src_text_dict else 3
    tmp_row.append(txt_src)
    
    # Calculamos el vector generado por el analisis de sentimiento
    tweet = data.loc[i,"text_tweet"]
    
    f.write(tweet + "\n")
    
    extractor = lbsa.FeatureExtractor(sa_lexicon, op_lexicon)
    
    #print(i, tweet)
    sentimental = extractor.process(tweet)    
    tmp_row.extend(sentimental)
    
    # Finalmente agregamos la clase 
    tmp_row.append(data.loc[i,"class"])
    
    data_array.append(tmp_row)
    
# Guardamos el archivo separado por tabs
np.savetxt("data_train_test.tsv", data_array, delimiter="\t")

f.close()
Total filas:  9598

Redes Neuronales

In [10]:
from sklearn.model_selection import train_test_split  
from sklearn.preprocessing import StandardScaler  
from sklearn.neural_network import MLPClassifier  
from sklearn.metrics import classification_report, confusion_matrix  

names = ['rt_count', 'followers_count', 'src_tweet', 'anger', 'anticipation', 
         'disgust', 'fear', 'joy', 'sadness', 'surprise', 'trust', 'positive', 
         'negative', 'class']

data = pd.read_csv("data_train_test.tsv", sep="\t", names=names)  

# Atributos
X = data.iloc[:, 0:len(data.columns)-2]
# Clases
y = data.iloc[:, len(data.columns)-1]
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.20)  

# Normalize, standarize
scaler = StandardScaler()  
scaler.fit(X_train)
X_train = scaler.transform(X_train)  
X_test = scaler.transform(X_test) 

mlp = MLPClassifier(hidden_layer_sizes=(10, 10), max_iter=1000)  
mlp.fit(X_train, y_train.values.ravel()) 

predictions = mlp.predict(X_test)  

con_mat = confusion_matrix(y_test,predictions)
#print("Matriz de confusión \n", con_mat, "\n") 

labels = ["True", "False"]

ax = plt.axes()
df_cm = pd.DataFrame(con_mat, index = [i for i in labels], columns = [i for i in labels],  dtype='int32')
sn.heatmap(df_cm, annot=True,  fmt='g')
ax.set_title('Matriz de confusión: Red Neuronal')

print("Accuracy Total: ", (con_mat[0][0]+con_mat[1][1])/sum(sum(con_mat)))
print(classification_report(y_test,predictions)) 

plt.savefig("sentiment_nn.png", dpi=300)
Accuracy Total:  0.70625
              precision    recall  f1-score   support

         0.0       0.73      0.87      0.80      1258
         1.0       0.62      0.39      0.48       662

   micro avg       0.71      0.71      0.71      1920
   macro avg       0.67      0.63      0.64      1920
weighted avg       0.69      0.71      0.69      1920

Support Vector Machine

In [11]:
from sklearn.svm import SVC  # support vector machine classifier

svm = SVC()
svm.fit(X_train, y_train)

predictions_3 = svm.predict(X_test)  

con_mat_3 = confusion_matrix(y_test,predictions_3)
#print("Matriz de confusión \n", con_mat_3, "\n") 

labels = ["True", "False"]

ax = plt.axes()
df_cm = pd.DataFrame(con_mat_3, index = [i for i in labels], columns = [i for i in labels],  dtype='int32')
sn.heatmap(df_cm, annot=True,  fmt='g')
ax.set_title('Matriz de confusión: SVN')

print("Accuracy Total: ", (con_mat_3[0][0]+con_mat_3[1][1])/sum(sum(con_mat_3)))
print(classification_report(y_test,predictions_3)) 

plt.savefig("sentiment_svn.png", dpi=300)
Accuracy Total:  0.7010416666666667
              precision    recall  f1-score   support

         0.0       0.71      0.92      0.80      1258
         1.0       0.65      0.28      0.39       662

   micro avg       0.70      0.70      0.70      1920
   macro avg       0.68      0.60      0.60      1920
weighted avg       0.69      0.70      0.66      1920

Problemas encontrados

Los nuevos resultados entregan aproximadamente un 10% menos de precisión que los obtenidos en hito II donde solo se utilizó un dataset, por lo cual es posible notar que un modelo basado solo en análisis de sentimientos no es suficiente apra resulver este problema.

Al momento de entrenar los modelos anteriormente expuestos para la nueva data, se pudo evidenciar una baja precisión (accuracy), lo cual se puede deber al hecho que emociones como la ira o el miedo siempre predominan, que sea antes o después de un ataque y lo cual hace que le quite explicación a la variabilidad a la data como para poder hacer una buena clasificación con esta información. Intentamos agregar otros atributos para clasificar como la fecha emisión del tweet pero los resultados no cambiaron. Por lo tanto, otro enfoque que se tomó para poder utilizar la información de los tweets y mejorar los algoritmos de clasificación fue el uso de "bag of words".

Nuevo modelo de clasificación: TF-IDF

Se implementó un nuevo modelo de clasificación utilizando TF-IDF o "Term frequency – Inverse document frequency" que traducido al español es "Frecuencia de términos – Frecuencia inversa del documento" el cual otorga una medida numérica que expresa cuán relevante es una palabra para un documento en una colección de estos.

El valor TF-IDF aumenta proporcionalmente al número de veces que una palabra aparece en el documento, pero es compensada por la frecuencia de la palabra en la colección de documentos.

Utilizando la libreria sklearn se generó un vector de 1500 caracteristicas usando TF-IDF, para esto fue necesario pre procesar lso tweets nuevamente, elimando stop words y "lemmatizando" para poder usar el método de Bag of Words apra clasificar.

In [3]:
# Vector de caracteristicas sentimeintos + tfidf, se almacena en un archivo diferente

from sklearn.feature_extraction.text import HashingVectorizer
from sklearn.feature_extraction.text import CountVectorizer  
from sklearn.feature_extraction.text import TfidfTransformer  

from nltk.stem import WordNetLemmatizer


import nltk

nltk.download('wordnet')

stemmer = WordNetLemmatizer()

filecp = codecs.open("data/merge.tsv", encoding = 'utf8')
data = pd.read_csv(filecp, sep="\t", encoding="utf-8", )
data.reset_index(drop=True)

# Creamos un arreglo vacío en el que se agregaran los vectores con los atributos
# usados durante el entrenamiento para cada fila
tweet_array = []

# Obtenemos la cantidad de filas
rows = data["class"].count()

for i in range(rows):
    
    tweet = data.loc[i,"text_tweet"]        
    # Limpiamos el tweet
    tweet = [stemmer.lemmatize(word) for word in tweet]
    tweet = ''.join(tweet)
      
    tweet_array.append(tweet)

    
vectorizer = CountVectorizer(max_features=1500, min_df=5, max_df=0.7, stop_words='english')  
X = vectorizer.fit_transform(tweet_array).toarray() 

tfidfconverter = TfidfTransformer()  
feature_vect = tfidfconverter.fit_transform(X).toarray()  


# Creamos un arreglo vacío en el que se agregaran los vectores con los atributos
# usados durante el entrenamiento para cada fila
data_array = []

print("Total filas: ", rows)

src_text_dict = {
                "Twitter for iPhone":0,
                "Twitter Web Client":1,
                "Twitter for Android":2
                }

sa_lexicon = lbsa.get_lexicon('sa', language='english', source='nrc')
op_lexicon = lbsa.get_lexicon('opinion', language='english', source='nrc')


for i in range(rows):

    rt_count = data.loc[i,"rt_count"] if data.loc[i,"rt_count"] else 0
    followers_count = data.loc[i,"followers_count"] if data.loc[i,"followers_count"] else 0
    tmp_row = [rt_count, followers_count]
    
    src = data.loc[i,"src_text"]
    txt_src = src_text_dict[src] if src in src_text_dict else 3
    tmp_row.append(txt_src)
    
    # Calculamos el vector generado por el analisis de sentimiento
    tweet = data.loc[i,"text_tweet"]
    
    extractor = lbsa.FeatureExtractor(sa_lexicon, op_lexicon)
    
    sentimental = extractor.process(tweet)    
    tmp_row.extend(sentimental)   
    
    tmp_row.extend(feature_vect[i])
    
    # Finalmente agregamos la clase 
    tmp_row.append(data.loc[i,"class"])
    
    data_array.append(tmp_row)
    
# Guardamos el archivo separado por tabs
np.savetxt("data_train_test2.tsv", data_array, delimiter="\t")

print(len(data_array))
[nltk_data] Downloading package wordnet to /home/joaquin/nltk_data...
[nltk_data]   Package wordnet is already up-to-date!
Total filas:  9598
9598
In [5]:
# Test net, solo utiliza el vector generado por tfidf
from sklearn.model_selection import train_test_split  
from sklearn.preprocessing import StandardScaler  
from sklearn.neural_network import MLPClassifier  
from sklearn.metrics import classification_report, confusion_matrix  

data = pd.read_csv("data_train_test2.tsv", sep="\t")  


# Atributos
X = data.iloc[:, 0:len(data.columns)-2]
# Si queremos solo el vector generado por tfidf (1500 caracteristicas)
X = data.iloc[:, len(data.columns)-1502:len(data.columns)-2]
# Clases, se encuentran en la ultima columna
y = data.iloc[:, len(data.columns)-1]

print(len(feature_vect))
print(len(y))
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.20)  

# Normalize, standarize
scaler = StandardScaler()  
scaler.fit(X_train)
X_train = scaler.transform(X_train)  
X_test = scaler.transform(X_test) 

mlp = MLPClassifier(hidden_layer_sizes=(250, 250), max_iter=2500, verbose=False)  
mlp.fit(X_train, y_train.values.ravel()) 

predictions = mlp.predict(X_test)  

con_mat = confusion_matrix(y_test,predictions)
#print("Matriz de confusión \n", con_mat, "\n") 

labels = ["True", "False"]

ax = plt.axes()
df_cm = pd.DataFrame(con_mat, index = [i for i in labels], columns = [i for i in labels],  dtype='int32')
sn.heatmap(df_cm, annot=True,  fmt='g')
ax.set_title('Matriz de confusión: Red Neuronal')

print("Accuracy Total: ", (con_mat[0][0]+con_mat[1][1])/sum(sum(con_mat)))
print(classification_report(y_test,predictions)) 


#plt.savefig("tfidf_nn.png", dpi=300)
9598
9597
Accuracy Total:  0.8302083333333333
              precision    recall  f1-score   support

         0.0       0.87      0.87      0.87      1282
         1.0       0.74      0.74      0.74       638

   micro avg       0.83      0.83      0.83      1920
   macro avg       0.81      0.81      0.81      1920
weighted avg       0.83      0.83      0.83      1920

Los resultados obtenidos son muy superiores a los observados utilizando solo análisis de sentimientos, más aún considerando que estos resultados pueden mejorar modificando lso aprametros de la red y el vector de características.

Conclusiones finales

Del trabajo semestral realizado se desprenden las siguientes conclusiones:

  1. Análisis de sentimientos no es suficiente para resolver el problema planteado debido a que bajan las métricas de ajuste como el accuracy al momento de utilizar modelos que incorporan este tipo de variables. Por lo tanto, se requiere utilizar otro tipo de metodología de estudio para poder desarrollar buenos modelos.
  2. Ciertos modelos se adaptan bien a dataset específicos, pero fracasan al ser generalizados. En el caso del proyecto, sucedió que se obtenían buenas métricas cuando se utilizaba el dataset de Finsbury, pero se presentaron inconvenientes al momento de evaluar su poder predictivo en las bases de datos de los otros tres dataset.
  3. Bag of words se comporta bien para los 4 datasets.
  4. No se descartan las posibles mejoras al modelo de bag of words con tf idf.
In [0]: